#include "GLObject.h"


GLObject::GLObject(GLObject* obj)
{
    reset();
    parent = obj;
    rootObject = NULL;
    render_box = false;
}

GLObject::~GLObject()
{
    destroyObjects();
    destroyBehaviors();
}

void GLObject::reset()
{
    model = NULL;
    texture = NULL;
    color = Color::White;
    scale = 1.0f;
    box_size.set(1.0f, 1.0f, 1.0f);
    selectId = -1;
}

void GLObject::render(int flags)
{
    onPreRender();
    glPushMatrix();
        glTranslatef(position.x, position.y, position.z);
        glRotatef(rotation.x, 1, 0, 0);
        glRotatef(rotation.y, 0, 1, 0);
        glRotatef(rotation.z, 0, 0, 1);
        glScalef(scale, scale, scale);
        glColor(color);
        if ((flags == GLRENDER_NORMAL) ||
            (flags == GLRENDER_SELECT && selectId > -1))
        {
            if (flags == GLRENDER_SELECT)
                glPushName(selectId);
            onRender();
            foreach (GLBehavior*, bhv, behaviors)
            {
                bhv->onRender();
            }
        }
        foreach (GLObject*, obj, children)
        {
            obj->render(flags);
        }
    glPopMatrix();
    onPostRender();
}

void GLObject::update(float dt)
{
    onUpdate(dt);
    foreach (GLBehavior*, bhv, behaviors)
    {
        bhv->onUpdate(dt);
    }
    foreach (GLObject*, obj, children)
    {
        obj->update(dt);
    }
}

int GLObject::pickObjectId(int x, int y, float sense)
{
    glBeginPicking(x, y, sense);
    render(GLRENDER_SELECT);
    return glEndPicking();
}

void GLObject::onRender()
{
    if (model)
    {
        if (texture)
        {
            texture->enable();
            model->render(false);
            texture->disable();
        }
        else
        {
            model->render(true);
        }
    }
    else if (render_box)
    {
        glPushMatrix();
        glTranslatef(box_center.x, box_center.y, box_center.z);
        glRenderCube(box_size.x, box_size.y, box_size.z);
        glPopMatrix();
    }
}

GLObject* GLObject::createObject()
{
    GLObject* obj = new GLObject(this);
    children.push_back(obj);
    return obj;
}

void GLObject::destroyObjects()
{
    foreach (GLObject*, obj, children)
    {
        obj->destroyObjects();
        delete obj;
    }
    children.clear();
}

void GLObject::destroyBehaviors()
{
    foreach (GLBehavior*, bhv, behaviors)
    {
        delete bhv;
    }
    behaviors.clear();
}

GLObject* GLObject::importXml(const char* filename)
{
    TiXmlDocument doc(filename);
	if (doc.LoadFile())
	{
		TiXmlElement* root = doc.FirstChildElement("root");
		parseXmlNode(root, this);
		return this;
	}
    return NULL;
}

void GLObject::parseXmlNode(TiXmlElement* elem, GLObject* root)
{
    if (root != this)
    {
        setRootObject(root);
        setColor(root->color);
    }
    const char *s_pos = elem->Attribute("pos");
    const char *s_opos = elem->Attribute("opos");
    const char *s_osize = elem->Attribute("osize");
    float x, y, z;
    if (s_pos)
    {
        sscanf(s_pos, "%f %f %f", &x, &y, &z);
        position.set(x, y, z);
    }
    if (s_opos)
    {
        sscanf(s_opos, "%f %f %f", &x, &y, &z);
        box_center.set(x, y, z);
    }
    if (s_osize)
    {
        sscanf(s_osize, "%f %f %f", &x, &y, &z);
        box_size.set(x, y, z);
        render_box = true;
    }
    //part event
    GLObject* po = this;
    while (po->parent)
    {
        po->parent->onNewPart(this);
        po = po->parent;
    }
	//recursion
	TiXmlElement* child = elem->FirstChildElement();
	while (child)
	{
        GLObject* obj = createObject();
        obj->name = child->Value();
		obj->parseXmlNode(child, root);
		child = child->NextSiblingElement();
	}
}



